home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / src / newmbox.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-13  |  35.5 KB  |  1,047 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: newmbox.c,v 5.26 1993/05/14 03:55:13 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.26 $   $State: Exp $
  6.  *
  7.  *            Copyright (c) 1988-1992 USENET Community Trust
  8.  *            Copyright (c) 1986,1987 Dave Taylor
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log: newmbox.c,v $
  17.  * Revision 5.26  1993/05/14  03:55:13  syd
  18.  * The recent feature addition for the "readmsginc" variable did not modify
  19.  * the output statement that is used when MMDF is defined.  The following
  20.  * patch makes the variable work on MMDF systems.
  21.  * From: Larry Philps <larryp@sco.COM>
  22.  *
  23.  * Revision 5.25  1993/05/08  20:25:33  syd
  24.  * Add sleepmsg to control transient message delays
  25.  * From: Syd
  26.  *
  27.  * Revision 5.24  1993/05/08  18:56:16  syd
  28.  * created a new elmrc variable named "readmsginc".  This specifies an
  29.  * increment by which the message count is updated.  If this variable is
  30.  * set to, say, 25, then the message count will only be updated every 25
  31.  * messages, displaying 0, 25, 50, 75, and so forth.  The default value
  32.  * of 1 will cause Elm to behave exactly as it currently does in PL21.
  33.  * From: Eric Peterson <epeterso@encore.com>
  34.  *
  35.  * Revision 5.23  1993/04/16  04:03:18  syd
  36.  * *** empty log message ***
  37.  *
  38.  * Revision 5.22  1993/02/09  19:36:52  syd
  39.  * STDC declares rewind
  40.  * From: Syd
  41.  *
  42.  * Revision 5.21  1993/02/03  17:12:53  syd
  43.  * move more declarations to defs.h, including sleep
  44.  * From: Syd
  45.  *
  46.  * Revision 5.20  1993/02/03  15:26:13  syd
  47.  * protect atol in ifndef __STDC__ as some make it a macro, and its in stdlib.h
  48.  *
  49.  * Revision 5.19  1993/01/27  20:45:55  syd
  50.  * When elm exits because a spool mailbox is used, it should do a Raw(OFF) so
  51.  * that the error message get's printed on the right screen.
  52.  * From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
  53.  *
  54.  * Revision 5.18  1993/01/27  20:44:27  syd
  55.  * Correct MMDF syntax problems and newmail botches.
  56.  * From: chip@chinacat.unicom.com (Chip Rosenthal)
  57.  *
  58.  * Revision 5.17  1993/01/20  03:37:16  syd
  59.  * Nits and typos in the NLS messages and corresponding default messages.
  60.  * From: dwolfe@pffft.sps.mot.com (Dave Wolfe)
  61.  *
  62.  * Revision 5.16  1993/01/20  03:02:19  syd
  63.  * Move string declarations to defs.h
  64.  * From: Syd
  65.  *
  66.  * Revision 5.15  1993/01/19  05:20:32  syd
  67.  * On a resync, the temp file was being reopened in *append*
  68.  * mode, thus the fseek that tried to back up the file pointer had no
  69.  * effect.
  70.  * From: Larry Philps <larryp@sco.COM>
  71.  *
  72.  * Revision 5.14  1993/01/19  05:12:22  syd
  73.  * read_headers() in src/newmbox.c assumes that Mime-Version preceeds
  74.  * Content-Type in the headers. I removed that assumption.
  75.  * From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
  76.  *
  77.  * Revision 5.13  1993/01/19  05:07:05  syd
  78.  * Trim erroreous extra log entry
  79.  * From: Syd
  80.  *
  81.  * Revision 5.12  1993/01/19  04:47:12  syd
  82.  * Significant changes to provide consistent Date and From_ header
  83.  * cracking.  Overhauled date utilities and moved into library.  Moved
  84.  * real_from() into library.  Modified frm, newmail, and readmsg utilities
  85.  * to use library version of real_from().  Moved get_word() from Elm
  86.  * source into library.  Added new library routines atonum() and strfcpy().
  87.  * Fixed trailing backslash bug in len_next().
  88.  * From: chip@chinacat.unicom.com (Chip Rosenthal)
  89.  *
  90.  * Revision 5.11  1992/12/11  01:45:04  syd
  91.  * remove sys/types.h include, it is now included by defs.h
  92.  * and this routine includes defs.h or indirectly includes defs.h
  93.  * From: Syd
  94.  *
  95.  * Revision 5.10  1992/12/07  04:31:38  syd
  96.  * Fix typo
  97.  * From: Syd
  98.  *
  99.  * Revision 5.9  1992/11/26  00:46:13  syd
  100.  * changes to first change screen back (Raw off) and then issue final
  101.  * error message.
  102.  * From: Syd
  103.  *
  104.  * Revision 5.8  1992/11/22  00:08:45  syd
  105.  * I was playing with the metamail stuff and Sun's Openwindows Mailtool
  106.  * and discovered that I was able to 'display' messages generated with
  107.  * Mailtool in elm using metamail.  This marks the Sun Attachments as
  108.  * needing metamail.
  109.  * From: Lutz Brunke <brunke@dkrz-hamburg.dbp.de>
  110.  *
  111.  * Revision 5.7  1992/11/14  21:49:42  syd
  112.  * I think that the code in 'newmbox.c' which handles bad 'Content-length'
  113.  * entries is incomplete. The file-ptr for the mail file is
  114.  * backed up, but the file-ptr of the temp file WAS LEFT UNMODIFIED !
  115.  * From langesw.ssw.de!root Wed Nov 11 14:28:57 1992
  116.  *
  117.  * Revision 5.6  1992/11/07  20:05:52  syd
  118.  * change to use header_cmp to allow for linear white space around the colon
  119.  * From: Syd
  120.  *
  121.  * Revision 5.5  1992/11/07  16:08:52  syd
  122.  * add tolerance for incorrect content length line
  123.  * From: Syd
  124.  *
  125.  * Revision 5.4  1992/10/31  18:52:51  syd
  126.  * Corrections to Unix date parsing and time zone storage
  127.  * From: eotto@hvlpa.att.com
  128.  *
  129.  * Revision 5.3  1992/10/25  01:47:45  syd
  130.  * fixed a bug were elm didn't call metamail on messages with a characterset,
  131.  * which could be displayed by elm itself, but message is encoded with QP
  132.  * or BASE64
  133.  * From: Klaus Steinberger <Klaus.Steinberger@Physik.Uni-Muenchen.DE>
  134.  *
  135.  * Revision 5.2  1992/10/24  12:51:34  syd
  136.  * Fixes SysV style forwarding
  137.  * From: Baruch Cochavy <bcochavy@ilux39.intel.com>
  138.  *
  139.  * Revision 5.1  1992/10/03  22:58:40  syd
  140.  * Initial checkin as of 2.4 Release at PL0
  141.  *
  142.  *
  143.  ******************************************************************************/
  144.  
  145. /**  read new folder **/
  146.  
  147. #include <ctype.h>
  148. #include "headers.h"
  149. #include "s_elm.h"
  150.  
  151. #ifdef BSD
  152. #undef tolower        /* we have our own "tolower" routine instead! */
  153. #endif
  154.  
  155. #include <sys/stat.h>
  156. #include <errno.h>
  157.  
  158. #ifdef I_TIME
  159. #  include <time.h>
  160. #endif
  161. #ifdef I_SYSTIME
  162. #  include <sys/time.h>
  163. #endif
  164.  
  165. extern int errno;
  166.  
  167. char *error_description();
  168. long bytes();
  169. #ifndef __STDC__ /* avoid problemswith systems that declare atol as a macro */
  170. extern void rewind();
  171. extern long atol();
  172. #endif
  173.  
  174. int
  175. newmbox(new_file, adds_only)
  176. char *new_file;
  177. int adds_only;
  178. {
  179.     /** Read a folder.
  180.  
  181.         new_file    - name of folder  to read. It is up to the calling
  182.               function to make sure that the file can be
  183.               read by the user. This is not checked in this
  184.               function. The reason why it is not checked here
  185.               is due to the situation where the user wants to
  186.               change folders: the new folder must be checked
  187.               for access *before* leaving the old one, which
  188.               is before this function gets called.
  189.         adds_only    - set if we only want to read newly added messages to
  190.                 same old folder.
  191.  
  192.     **/
  193.  
  194.     int  same_file;
  195.     int  new_folder_type;
  196.     int err;
  197.     char new_tempfile[SLEN];
  198.  
  199.     /* determine type of new mailfile and calculate temp file name */
  200.     if((new_folder_type = get_folder_type(new_file)) == SPOOL)
  201.       mk_temp_mail_fn(new_tempfile, new_file);
  202.     else
  203.       *new_tempfile = '\0';
  204.  
  205.     /* determine whether we are changing files */
  206.     same_file = !(strcmp(new_file, cur_folder));
  207.  
  208.     /* If we are changing files and we are changing to a spool file,
  209.      * make sure there isn't a temp file for it, because if
  210.      * there is, someone else is using ELM to read the new file,
  211.      * and we don't want to be reading it at the same time.
  212.      */
  213.     if((new_folder_type == SPOOL) && (!same_file)) {
  214.       if (access(new_tempfile, ACCESS_EXISTS) != -1) {
  215.         Raw(OFF);
  216.         ClearScreen();
  217.         Centerline(15, catgets(elm_msg_cat, ElmSet, ElmAlreadyRunning1,
  218.         "You seem to have ELM already reading this mail!"));
  219.         Centerline(17, catgets(elm_msg_cat, ElmSet, ElmAlreadyRunning2,
  220.         "You may not have two copies of ELM running simultaneously.  -- Exiting --"));
  221.         Centerline(18, catgets(elm_msg_cat, ElmSet, ElmAlreadyRunning3,
  222.         "If this is in error, then you'll need to remove the following file:"));
  223.         Centerline(19, new_tempfile);
  224.         MoveCursor(LINES, 0);  /* so shell prompt upon exit is on newline */
  225.         silently_exit();
  226.       }
  227.     }
  228.  
  229.     /* If we were reading a spool file and we are not just reading
  230.      * in the additional new messages to the same file, we need to
  231.      * remove the corresponding tempfile.
  232.      */
  233.  
  234.     if((folder_type == SPOOL) && !adds_only) {
  235.       if (access(cur_tempfolder, ACCESS_EXISTS) != -1) {
  236.         if (unlink(cur_tempfolder) != 0) {
  237.           error2(catgets(elm_msg_cat, ElmSet, ElmSorryCantUnlinkTemp,
  238.         "Sorry, can't unlink the temp file %s [%s]!\n\r"),
  239.             cur_tempfolder, error_description(errno));
  240.           silently_exit();
  241.         }
  242.       }
  243.     }
  244.  
  245.     /* Okay! Now establish this new file as THE file */
  246.     strcpy(cur_folder, new_file);
  247.     folder_type = new_folder_type;
  248.     strcpy(cur_tempfolder, new_tempfile);
  249.  
  250.     clear_error();
  251.     clear_central_message();
  252.  
  253.     if (mailfile != NULL)
  254.       (void) fclose(mailfile);  /* close it first, to avoid too many open */
  255.  
  256.     if ((mailfile = fopen(cur_folder,"r")) == NULL)  {
  257.       if (errno != ENOENT ) { /* error on anything but file not exist */
  258.         err = errno;
  259.         MoveCursor(LINES,0);
  260.         Raw(OFF);
  261.         printf(catgets(elm_msg_cat, ElmSet, ElmFailOnOpenNewmbox,
  262.             "\nfail on open in newmbox, open %s failed!!\n"),
  263.             cur_folder);
  264.         printf("** %s. **\n", error_description(err));
  265.         dprint(1, (debugfile, "fail on open in newbox, file %s!!\n",
  266.             cur_folder));
  267.         rm_temps_exit();
  268.       }
  269.       else {
  270.         mailfile_size = 0;         /* must non-existant folder */
  271.         message_count = 0;
  272.         selected = 0;
  273.       }
  274.     } else {                          /* folder exists, read headers */
  275.       read_headers(adds_only);
  276.     }
  277.  
  278.     if(!same_file)        /* limit mode off if this is a new file */
  279.       selected = 0;
  280.     if (!adds_only)        /* limit mode off if recreating headers */
  281.       selected = 0;        /* because we loose the 'Visible' flag */
  282.  
  283.     dprint(1, (debugfile,
  284.       "New folder %s type %s temp file %s (%s)\n", cur_folder, 
  285.       (folder_type == SPOOL ? "spool" : "non-spool"),
  286.       (*cur_tempfolder ? cur_tempfolder : "none"), "newmbox"));
  287.  
  288.     return(0);
  289. }
  290.  
  291. int
  292. get_folder_type(filename)
  293. char *filename;
  294. {
  295.     /** returns the type of mailfile filename is
  296.         NO_NAME = no name
  297.         SPOOL = consisting only of mailhome plus base file name
  298.             (no intervening directory name)
  299.         NON_SPOOL = a name that is not SPOOL type above
  300.      **/
  301.  
  302.     char *last_slash;
  303.  
  304.     /* if filename is null or is of zero length */
  305.     if((filename == NULL) || (*filename == '\0'))
  306.       return(NO_NAME);
  307.  
  308.     /* if filename begins with mailhome,
  309.      * and there is a slash in filename,
  310.      * and there is a filename after it (i.e. last slash is not last char),
  311.      * and the last character of mailhome is last slash in filename,
  312.      * it's a spool file .
  313.      */
  314.     if((first_word(filename, mailhome)) &&
  315.       ((last_slash = rindex(filename, '/')) != NULL) &&
  316.       (*(last_slash+1) != '\0') &&
  317.       (filename + strlen(mailhome) - 1 == last_slash))
  318.         return(SPOOL);
  319.     /* if file name == default mailbox, its a spool file also
  320.      * even if its not in the spool directory. (SVR4)
  321.      */
  322.     if (strcmp(filename, defaultfile) == 0)
  323.         return(SPOOL);
  324.  
  325.     return(NON_SPOOL);
  326. }
  327.  
  328. mk_temp_mail_fn(tempfn, mbox)
  329. char *tempfn, *mbox;
  330. {
  331.     /** create in tempfn the name of the temp file corresponding to
  332.         mailfile mbox. Mbox is presumed to be a file in mailhome;
  333.         Strangeness may result if it is not!
  334.      **/
  335.  
  336.     char *cp;
  337.  
  338.     sprintf(tempfn, "%s%s", default_temp, temp_mbox);
  339.     if((cp = rindex(mbox, '/')) != NULL) {
  340.       cp++;
  341.       if (strcmp(cp, "mbox") == 0 || strcmp(cp, "mailbox") == 0 ||
  342.         strcmp(cp, "inbox") == 0 || *cp == '.')
  343.         strcat(tempfn, username);
  344.       else
  345.         strcat(tempfn, cp);
  346.     }
  347. }
  348.  
  349. int
  350. read_headers(add_new_only)
  351. int add_new_only;
  352. {
  353.     /** Reads the headers into the headers[] array and leaves the
  354.         file rewound for further I/O requests.   If the file being
  355.         read is a mail spool file (ie incoming) then it is copied to
  356.         a temp file and closed, to allow more mail to arrive during 
  357.         the elm session.  If 'add_new_only' is set, the program will copy
  358.         the status flags from the previous data structure to the new 
  359.         one if possible and only read in newly added messages.
  360.     **/
  361.  
  362.     FILE *temp;
  363.     struct header_rec *current_header = NULL;
  364.     char buffer[LONG_STRING], tbuffer[LONG_STRING], *c;
  365.     long fbytes = 0L, line_bytes = 0L, content_start = 0L,
  366.       content_remaining = -1L, lines_start = 0L;
  367.     register long line = 0;
  368.     register int count = 0, another_count,
  369.       subj = 0, copyit = 0, in_header = FALSE;
  370.     int count_x, count_y = 17, err;
  371.     int in_to_list = FALSE, forwarding_mail = FALSE, first_line = TRUE,
  372.       content_length_found = FALSE;
  373.  
  374.     static int first_read = 0;
  375. #ifdef MMDF
  376.         int newheader = 0;
  377. #endif /* MMDF */
  378.  
  379.     if (folder_type == SPOOL) {
  380.       lock(INCOMING);    /* ensure no mail arrives while we do this! */
  381.       if (! add_new_only) {
  382.         if (access(cur_tempfolder, ACCESS_EXISTS) != -1) {
  383.           /* Hey!  What the hell is this?  The temp file already exists? */
  384.           /* Looks like a potential clash of processes on the same file! */
  385.           unlock();                     /* so remove lock file! */
  386.           error(catgets(elm_msg_cat, ElmSet, ElmWhatsThisTempExists,
  387.         "What's this?  The temp folder already exists??"));
  388.           if (sleepmsg > 0)
  389.             sleep(sleepmsg);
  390.           error(catgets(elm_msg_cat, ElmSet, ElmIGiveUp,
  391.         "Ahhhh... I give up."));
  392.           silently_exit();    /* leave without tampering with it! */
  393.         }
  394.         if ((temp = fopen(cur_tempfolder,"w")) == NULL) {
  395.          err = errno;
  396.          unlock();    /* remove lock file! */
  397.          MoveCursor(LINES, 0);
  398.          Raw(OFF);
  399.          printf(catgets(elm_msg_cat, ElmSet, ElmCouldntOpenForTemp,
  400.              "\nCouldn't open file %s for use as temp file.\n"),
  401.              cur_tempfolder);
  402.          printf("** %s. **\n", error_description(err));
  403.          dprint(1, (debugfile,
  404.                 "Error: Couldn't open file %s as temp mbox.  errno %s (%s)\n",
  405.              cur_tempfolder, error_description(err), "read_headers"));
  406.          rm_temps_exit();
  407.         }
  408.        copyit++;
  409.        chown(cur_tempfolder, userid, groupid);
  410.        chmod(cur_tempfolder, 0700);    /* shut off file for other people! */
  411.      }
  412.      else {
  413.        /*
  414.         * Used to open this file for append, however with the new
  415.         * content length stuff, we might want to fseek backwards
  416.         * in the file.  This will fail if append mode is set, so
  417.         * we can not do that anymore.  Since there is no way to
  418.         * fopen a file for write-only without either truncating it
  419.         * or putting it into append mode (neither of which is right
  420.         * for us), we do a "r+" open (also opens the file for reading),
  421.         * then fseek to the end of the file.
  422.         */
  423.        if ((temp = fopen(cur_tempfolder,"r+")) == NULL) {
  424.          err = errno;
  425.          unlock();    /* remove lock file! */
  426.          MoveCursor(LINES,0);
  427.          Raw(OFF);
  428.          printf(catgets(elm_msg_cat, ElmSet, ElmCouldntReopenForTemp,
  429.              "\nCouldn't reopen file %s for use as temp file.\n"),
  430.              cur_tempfolder);
  431.          printf("** %s. **\n", error_description(err));
  432.          dprint(1, (debugfile, 
  433.                 "Error: Couldn't reopen file %s as temp mbox.  errno %s (%s)\n",
  434.              cur_tempfolder, error_description(err), "read_headers"));
  435.          rm_temps_exit();
  436.         }
  437.        if (fseek(temp, 0, 2) == -1) {
  438.          err = errno;
  439.          unlock();    /* remove lock file! */
  440.          fclose(temp);
  441.          MoveCursor(LINES,0);
  442.          Raw(OFF);
  443.          printf(catgets(elm_msg_cat, ElmSet, ElmCouldntSeekTempEnd,
  444.              "\nCouldn't fseek to end of reopened temp mbox.\n"));
  445.          printf("** %s. **\n", error_description(err));
  446.          dprint(1, (debugfile, 
  447.                 "Error: Couldn't fseek to end of reopened temp mbox.  errno %s (%s)\n",
  448.              error_description(err), "read_headers"));
  449.          rm_temps_exit();
  450.         }
  451.        copyit++;
  452.       }
  453.     }
  454.  
  455.     if (! first_read++) {
  456.       ClearLine(LINES-1);
  457.       ClearLine(LINES);
  458.       if (add_new_only)
  459.         PutLine2(LINES, 0, catgets(elm_msg_cat, ElmSet, ElmReadingInMessage,
  460.              "Reading in %s, message: %d"),
  461.              cur_folder, message_count);
  462.       else
  463.         PutLine1(LINES, 0, catgets(elm_msg_cat, ElmSet, ElmReadingInMessage0,
  464.              "Reading in %s, message: 0"), cur_folder);
  465.       count_x = LINES;
  466.           count_y = 22 + strlen(cur_folder);
  467.     }
  468.     else {
  469.       count_x = LINES-2;
  470.       PutLine0(LINES-2, 0, catgets(elm_msg_cat, ElmSet, ElmReadingMessage0,
  471.         "Reading message: 0"));
  472.     }
  473.  
  474.     if (add_new_only) {
  475.        if (fseek(mailfile, mailfile_size, 0) == -1) {
  476.          err = errno;
  477.          MoveCursor(LINES, 0);
  478.          Raw(OFF);
  479.          MCprintf(catgets(elm_msg_cat, ElmSet, ElmCouldntSeekEndFolder,
  480.         "\nCouldn't seek to %ld (end of folder) in %s!\n"),
  481.         mailfile_size, cur_folder);    
  482.          printf("** %s. **\n", 1, error_description(err));
  483.          dprint(1, (debugfile,
  484.      "Error: Couldn't seek to end of folder %s: (offset %ld) Errno %s (%s)\n",
  485.             cur_folder, mailfile_size, error_description(err), "read_headers"));
  486.          emergency_exit();
  487.        }
  488.        count = message_count;        /* next available  */
  489.        fbytes = mailfile_size;        /* start correctly */
  490.     }
  491.  
  492.     /** find the size of the folder then unlock the file **/
  493.  
  494.     mailfile_size = bytes(cur_folder);
  495.     unlock();
  496.  
  497.     /** now let's copy it all across accordingly... **/
  498.  
  499.     while (fbytes < mailfile_size) {
  500.  
  501.       if ((line_bytes = mail_gets(buffer, LONG_STRING, mailfile)) == 0)
  502.         break;
  503.  
  504.       if (copyit)
  505.         if (fwrite(buffer, 1, line_bytes, temp) != line_bytes) {
  506.         err = errno;
  507.         MoveCursor(LINES, 0);
  508.         Raw(OFF);
  509.         printf(catgets(elm_msg_cat, ElmSet, ElmWriteToTempFailed,
  510.                 "\nWrite to temp file %s failed!!\n"),
  511.                 cur_tempfolder);
  512.         printf("** %s. **\n", error_description(err));
  513.         dprint(1, (debugfile, "Can't write to temp file %s!!\n",
  514.                cur_tempfolder));
  515.         rm_temps_exit();
  516.         }
  517.  
  518.       /* Fix below to increment line count ONLY if we got a full line.
  519.        * Input lines longer than the mail_gets buffer size would
  520.        * get counted each time a subsequent part of them was
  521.        * read in. This meant that when the faulty line count was used
  522.        * to display the message, part of the next message
  523.        * was displayed at the end of the message.
  524.        */
  525.       if(buffer[line_bytes - 1] == '\n') line++;
  526.  
  527.       if (fbytes == 0L || first_line) {     /* first line of file... */    
  528.         if (folder_type == SPOOL) {
  529.           if (first_word_nc(buffer, "forward to ")) {
  530.             set_central_message(catgets(elm_msg_cat, ElmSet, ElmMailBeingForwardTo,
  531.             "Mail being forwarded to %s"), 
  532.                        (char *) (buffer + 11));
  533.             forwarding_mail = TRUE;
  534.           }
  535.         }
  536.  
  537.         /** flush leading blank lines before next test... **/
  538.         if (line_bytes == 1) {
  539.           fbytes++;
  540.           continue;    
  541.         }
  542.         else
  543.           first_line = FALSE;
  544.               
  545. #ifdef MMDF
  546.         if (!forwarding_mail && strcmp(buffer, MSG_SEPARATOR) != 0 ) {
  547. #else
  548.         if (! first_word(buffer, "From ") && !forwarding_mail) {
  549. #endif /* MMDF */
  550.           MoveCursor(LINES,0);
  551.           Raw(OFF);
  552.           printf(catgets(elm_msg_cat, ElmSet, ElmFolderCorrupt,
  553.           "\nFolder is corrupt!!  I can't read it!!\n\n"));
  554.           fflush(stderr);
  555.           dprint(1, (debugfile, 
  556.                "\n**** First mail header is corrupt!! ****\n"));
  557.           dprint(1, (debugfile, "Line is;\n\t%s\n\n", buffer));
  558.               leave(0);
  559.         }
  560.       }
  561.  
  562.       if (content_remaining <= 0) {
  563. #ifdef MMDF
  564.         if (strcmp(buffer, MSG_SEPARATOR) == 0) {
  565.               newheader = !newheader;
  566. #else
  567.         if (first_word(buffer,"From ")) {
  568. #endif /* MMDF */
  569.           /** allocate new header pointers, if needed... **/
  570.  
  571.           if (count >= max_headers) {
  572.         struct header_rec **new_headers;
  573.         int new_max;
  574.  
  575.         new_max = max_headers + KLICK;
  576.         if (max_headers == 0) {
  577.           new_headers = (struct header_rec **)
  578.             malloc(new_max * sizeof(struct header_rec *));
  579.         }
  580.         else {
  581.           new_headers = (struct header_rec **)
  582.             realloc((char *) headers,
  583.             new_max * sizeof(struct header_rec *));
  584.         }
  585.         if (new_headers == NULL) {
  586.               MoveCursor(LINES,0);
  587.               Raw(OFF);
  588.           printf(catgets(elm_msg_cat, ElmSet, ElmCouldntAllocMemory,
  589.     "\n\nCouldn't allocate enough memory! Message #%d.\n\n"),
  590.               count);
  591.           leave(0);
  592.         }
  593.         headers = new_headers;
  594.         while (max_headers < new_max)
  595.           headers[max_headers++] = NULL;
  596.           }
  597.           
  598.           /** allocate new header structure, if needed... **/
  599.  
  600.           if (headers[count] == NULL) {
  601.         struct header_rec *h;
  602.  
  603.         if ((h = (struct header_rec *)
  604.               malloc(sizeof(struct header_rec))) == NULL) {
  605.               MoveCursor(LINES,0);
  606.               Raw(OFF);
  607.           printf(catgets(elm_msg_cat, ElmSet, ElmCouldntAllocMemory,
  608.     "\n\nCouldn't allocate enough memory! Message #%d.\n\n"),
  609.               count);
  610.           leave(0);
  611.         }
  612.         headers[count] = h;
  613.           }
  614.  
  615.           dprint(1, (debugfile, 
  616.            "\n**** Calling real_from for \"From_\" ****\n"));
  617.           if (real_from(buffer, headers[count])) {
  618.  
  619.             dprint(1, (debugfile, "\ncontent_remaining = %ld, content_start = %ld, lines_start = %ld, fbytes = %ld\n",
  620.             content_remaining, content_start, lines_start, fbytes));
  621.  
  622.         current_header = headers[count];
  623.  
  624.         current_header->offset = (long) fbytes;
  625.         current_header->content_length = -1; /* not found yet */
  626.         current_header->index_number = count+1;
  627.         content_length_found = FALSE;
  628.         /* set default status - always 'visible'  - and
  629.          * if a spool file, presume 'new', otherwise
  630.          * 'read', for the time being until overridden
  631.          * by a Status: header.
  632.          * We presume 'read' for nonspool mailfile messages
  633.          * to be compatible messages stored with older versions of elm,
  634.          * which didn't support a Status: header.
  635.          */
  636.         if(folder_type == SPOOL)
  637.           current_header->status = VISIBLE | NEW | UNREAD;
  638.         else
  639.           current_header->status = VISIBLE;
  640.  
  641.         strcpy(current_header->subject, "");    /* clear subj    */
  642.         strcpy(current_header->to, "");        /* clear to    */
  643.         strcpy(current_header->mailx_status, "");    /* clear status flags */
  644.         strcpy(current_header->time_menu, "");    /* clear menu date */
  645.         strcpy(current_header->messageid, "<no.id>"); /* set no id into message id */
  646.         current_header->encrypted = 0;        /* clear encrypted */
  647.         current_header->exit_disposition = UNSET;
  648.         current_header->status_chgd = FALSE;
  649.  
  650.         /* Set the number of lines for the _preceding_ message,
  651.          * but only if there was a preceding message and
  652.          * only if it wasn't calculated already. It would
  653.          * have been calculated already if we are only
  654.          * reading headers of new messages that have just arrived,
  655.          * and the preceding message was one of the old ones.
  656.          */
  657.         if ((count) && (!add_new_only || count > message_count)) {
  658.           headers[count-1]->lines = line;
  659.           if (headers[count-1]->content_length < 0)
  660.             headers[count-1]->content_length = fbytes - content_start;
  661.         }
  662.  
  663.         count++;
  664.         subj = 0;
  665.         line = 0;
  666.         in_header = TRUE;
  667.         if (count % readmsginc == 0)
  668.           PutLine1(count_x, count_y, "%d", count);
  669. #ifdef MMDF
  670.           } else if (newheader) {
  671.         current_header = headers[count];
  672.  
  673.         current_header->offset = (long) fbytes;
  674.         current_header->content_length = -1; /* not found yet */
  675.         current_header->index_number = count+1;
  676.  
  677.         /* set default status - always 'visible'  - and
  678.          * if a spool file, presume 'new', otherwise
  679.          * 'read', for the time being until overridden
  680.          * by a Status: header.
  681.          * We presume 'read' for nonspool mailfile messages
  682.          * to be compatible messages stored with older versions of elm,
  683.          * which didn't support a Status: header.
  684.          */
  685.         if(folder_type == SPOOL)
  686.           current_header->status = VISIBLE | NEW | UNREAD;
  687.         else
  688.           current_header->status = VISIBLE;
  689.  
  690.         strcpy(current_header->from, "");        /* clear from    */
  691.         strcpy(current_header->subject, "");    /* clear subj    */
  692.         strcpy(current_header->to, "");        /* clear to    */
  693.         strcpy(current_header->time_zone, "");    /* clear time zone name */
  694.         strcpy(current_header->time_menu, "");    /* clear menu date */
  695.         strcpy(current_header->mailx_status, "");    /* clear status flags */
  696.         strcpy(current_header->messageid, "<no.id>"); /* set no id into message id */
  697.         current_header->encrypted = 0;        /* clear encrypted */
  698.         current_header->exit_disposition = UNSET;
  699.         current_header->status_chgd = FALSE;
  700.  
  701.         /* Set the number of lines for the _preceding_ message,
  702.          * but only if there was a preceding message and
  703.          * only if it wasn't calculated already. It would
  704.          * have been calculated already if we are only
  705.          * reading headers of new messages that have just arrived,
  706.          * and the preceding message was one of the old ones.
  707.          */
  708.         if ((count) && (!add_new_only || count > message_count)) {
  709.           headers[count-1]->lines = line;
  710.           if (headers[count-1]->content_length < 0)
  711.             headers[count-1]->content_length = fbytes - content_start;
  712.         }
  713.  
  714.         count++;
  715.         subj = 0;
  716.         line = 0;
  717.         in_header = TRUE;
  718.         if (count % readmsginc == 0)
  719.           PutLine1(count_x, count_y, "%d", count);
  720.         dprint(1, (debugfile, 
  721.                  "\n**** Added header record ****\n"));
  722. #endif /* MMDF */
  723.           }
  724.         } else if (!forwarding_mail && count == 0) {
  725.           /* if this is the first "From" in file but the "From" line is
  726.            * not of the proper format, we've got a corrupt folder.
  727.            */
  728.           MoveCursor(LINES,0);
  729.           Raw(OFF);
  730.           printf(catgets(elm_msg_cat, ElmSet, ElmFolderCorrupt,
  731.           "\nFolder is corrupt!!  I can't read it!!\n\n"));
  732.           fflush(stderr);
  733.           dprint(1, (debugfile, 
  734.                "\n**** First mail header is corrupt!! ****\n"));
  735.           dprint(1, (debugfile, "Line is;\n\t%s\n\n", buffer));
  736.           leave(0);
  737.         } else if (in_header == FALSE && content_length_found == TRUE && line_bytes > 1) {
  738.         /* invalid content length, skip back to beginning of
  739.          * this messages text and ignore the content length
  740.          * field.  This requires restoring the current position
  741.          * in the spool file and the number of lines in the
  742.          * message.
  743.          */
  744.           if (fseek(mailfile, content_start, 0) == -1) {
  745.         err = errno;
  746.         MoveCursor(LINES, 0);
  747.         Raw(OFF);
  748.         printf(catgets(elm_msg_cat, ElmSet, ElmCouldntSeekBytesIntoFolder,
  749.            "\nCouldn't seek %ld bytes into folder.\n"),
  750.            mailfile_size);    
  751.         printf("** %s. **\n", 1, error_description(err));
  752.         dprint(1, (debugfile,
  753.       "Error: Couldn't seek folder %s: (offset %ld) Errno %s (%s)\n",
  754.            cur_folder, mailfile_size, error_description(err), "reset - read_headers"));
  755.         emergency_exit();
  756.           }
  757.           if (copyit)
  758.         if (fseek(temp, content_start, 0) == -1) {
  759.           err = errno;
  760.           MoveCursor(LINES, 0);
  761.           Raw(OFF);
  762.           printf(catgets(elm_msg_cat, ElmSet, ElmCouldntSeekBytesIntoTempFile,
  763.              "\nCouldn't seek %ld bytes into temp file.\n"),
  764.              mailfile_size);
  765.           printf("** %s. **\n", error_description(err));
  766.           dprint(1, (debugfile,
  767.     "Error: Couldn't seek temp file %s: (offset %ld) Errno %s (%s)\n",
  768.              cur_tempfolder, mailfile_size, error_description(err), "reset - read_headers"));
  769.           emergency_exit();
  770.         }
  771.           fbytes = content_start;
  772.           line = lines_start;
  773.           content_length_found = FALSE;
  774.           current_header->content_length = -1; /* mark as if not found yet */
  775.           line_bytes = 0;
  776.         }
  777.       }
  778.  
  779.       if (in_header == TRUE) {
  780. #ifdef MMDF
  781.         if (strcmp(buffer, MSG_SEPARATOR) == 0) {
  782.           /*
  783.            * This is disgusting, but the code below "knows" that
  784.            * headers all have colons in them.  However, the MMDF
  785.            * message separator is a header without a colon.  So,
  786.            * we put one there to make the rest of the logic work.
  787.            */
  788.           buffer[0] = ':';
  789.         } else if (first_word(buffer,"From ")) {
  790.           dprint(1, (debugfile, 
  791.            "\n**** Calling real_from for \"From_\" ****\n"));
  792.           real_from(buffer, current_header);
  793.         } else
  794. #endif /* MMDF */
  795.         if (header_cmp(buffer,">From", NULL))
  796.           parse_arpa_who(buffer, current_header->from, FALSE);
  797.         else if (first_word_nc(buffer,">From")) 
  798.           forwarded(buffer, current_header); /* return address */
  799.         else if (header_cmp(buffer,"Subject", NULL) ||
  800.              header_cmp(buffer,"Subj", NULL) ||
  801.              header_cmp(buffer,"Re", NULL)) {
  802.           if (! subj++) {
  803.         strfcpy(tbuffer, buffer, sizeof(tbuffer));
  804.             remove_header_keyword(tbuffer);
  805.             copy_sans_escape(current_header->subject, tbuffer, STRING);
  806.         remove_possible_trailing_spaces(current_header->subject);
  807.           }
  808.         }
  809.         else if (header_cmp(buffer,"From", NULL)) {
  810.           dprint(1, (debugfile, 
  811.            "\n**** Calling parse_arpa_who for \"From\" ****\n"));
  812. #ifdef MMDF
  813.           parse_arpa_who(buffer, current_header->from, TRUE);
  814. #else
  815.           parse_arpa_who(buffer, current_header->from, FALSE);
  816. #endif /* MMDF */
  817.  
  818.         }
  819.         else if (header_cmp(buffer, "Message-Id", NULL)) {
  820.           buffer[line_bytes - 1] = '\0';
  821.           strcpy(current_header->messageid,
  822.              (char *) buffer + 12);
  823.         }
  824.  
  825.         else if (header_cmp(buffer, "Content-Length", NULL)) {
  826.           buffer[line_bytes - 1] = '\0';
  827.           current_header->content_length = atol((char *) buffer + 15);
  828.           content_length_found = TRUE;
  829.         }
  830.  
  831.         else if (header_cmp(buffer, "Expires", NULL))
  832.           process_expiration_date((char *) buffer + 9, 
  833.                       &(current_header->status));
  834.         
  835.         /** when it was sent... **/
  836.  
  837.         else if (header_cmp(buffer, "Date", NULL)) {
  838.           dprint(1, (debugfile, 
  839.               "\n**** Calling parse_arpa_date for \"Date\" ****\n"));
  840.           strfcpy(tbuffer, buffer, sizeof(tbuffer));
  841.           remove_header_keyword(tbuffer);
  842.           parse_arpa_date(tbuffer, current_header);
  843.         }
  844.  
  845.         /** some status things about the message... **/
  846.  
  847.         else if ((header_cmp(buffer, "Priority", NULL) ||
  848.              header_cmp(buffer, "Importance", "2")) &&
  849.            !(header_cmp(buffer, "priority", "normal") ||
  850.              header_cmp(buffer, "priority", "non-urgent")))
  851.           current_header->status |= URGENT;
  852.         else if (header_cmp(buffer, "Sensitivity", "2"))
  853.           current_header->status |= PRIVATE;
  854.         else if (header_cmp(buffer, "Sensitivity", "3"))
  855.           current_header->status |= CONFIDENTIAL;
  856.         else if (header_cmp(buffer, "Content-Type", "mailform"))
  857.           current_header->status |= FORM_LETTER;
  858.         else if (header_cmp(buffer, "Action", NULL))
  859.           current_header->status |= ACTION;
  860. #ifdef    MIME
  861.         else if (header_cmp(buffer, MIME_HEADER_NAME, MIME_HEADER_VERSION))
  862.           current_header->status |= MIME_MESSAGE;
  863.         /* Next two lines for backward compatability to old drafts */
  864.         else if (header_cmp(buffer, MIME_HEADER_NAME, MIME_HEADER_OLDVERSION))
  865.           current_header->status |= MIME_MESSAGE;
  866.         /* Next two lines for minimal support for mail generated by
  867.          * Sun's Openwindows mailtool */
  868.         else if (header_cmp(buffer, "Content-Type", "X-"))
  869.           current_header->status |= MIME_MESSAGE|MIME_NOTPLAIN;
  870.         else if (header_cmp(buffer, MIME_HEADER_CONTENTTYPE, NULL)) {
  871.           if (! (current_header->status & MIME_NOTPLAIN) &&
  872.           notplain(buffer+strlen(MIME_CONTENTTYPE)))
  873.         current_header->status |= MIME_NOTPLAIN;
  874.         }
  875.         else if (header_cmp(buffer, MIME_HEADER_CONTENTENCOD, NULL)) {
  876.           if (needs_mmdecode(buffer+strlen(MIME_CONTENTENCOD)))
  877.         current_header->status |= MIME_NEEDDECOD;
  878.         }
  879. #endif /* MIME */
  880.  
  881.         /** next let's see if it's to us or not... **/
  882.  
  883.         else if (header_cmp(buffer, "To", NULL)) {
  884.           in_to_list = TRUE;
  885.           current_header->to[0] = '\0';    /* nothing yet */
  886.           figure_out_addressee((char *) buffer +3, 
  887.                    current_header->to);
  888.         }
  889.         else if (header_cmp(buffer, "Status", NULL)) {
  890.           strfcpy(tbuffer, buffer, sizeof(tbuffer));
  891.           remove_header_keyword(tbuffer);
  892.           strfcpy(current_header->mailx_status, tbuffer, WLEN);
  893.  
  894.           c = index(current_header->mailx_status, '\n');
  895.           if (c != NULL)
  896.         *c = '\0';
  897.           remove_possible_trailing_spaces(current_header->mailx_status);
  898.  
  899.           /* Okay readjust the status. If there's an 'R', message
  900.            * is read; if there is no 'R' but there is an 'O', message
  901.            * is unread. In any case it isn't new because a new message
  902.            * wouldn't have a Status: header.
  903.            */
  904.           if (index(current_header->mailx_status, 'R') != NULL)
  905.         current_header->status &= ~(NEW | UNREAD);
  906.           else if (index(current_header->mailx_status, 'O') != NULL) {
  907.         current_header->status &= ~NEW;
  908.         current_header->status |= UNREAD;
  909.           }
  910.         }
  911.  
  912.         else if (buffer[0] == LINE_FEED || buffer[0] == '\0') {
  913.           in_header = FALSE;    /* in body of message! */
  914.           in_to_list = FALSE;
  915.           content_remaining = current_header->content_length;
  916.           content_start = fbytes + 1;
  917.           lines_start = line;
  918.         }
  919.         if (in_header == TRUE) {
  920.            if ((!whitespace(buffer[0])) && index(buffer, ':') == NULL) {
  921.             in_header = FALSE;    /* in body of message! */
  922.             in_to_list = FALSE;
  923.             content_remaining = current_header->content_length;
  924.             content_start = fbytes;
  925.             lines_start = line;
  926.           }
  927.         }
  928.         if (in_to_list == TRUE) {
  929.           if (whitespace(buffer[0]))
  930.             figure_out_addressee(buffer, current_header->to);
  931.           else in_to_list = FALSE;
  932.         }
  933.       }
  934.       if (in_header == FALSE && first_word(buffer, START_ENCODE))
  935.         current_header->encrypted = 1;
  936.       fbytes += (long) line_bytes;
  937.       content_remaining -= (long) line_bytes;
  938.     }
  939.  
  940.     if (count) {
  941.       headers[count-1]->lines = line + 1;
  942.       if (headers[count-1]->content_length < 0)
  943.         headers[count-1]->content_length = fbytes - content_start;
  944.     }
  945.  
  946.     if (folder_type == SPOOL) {
  947.       unlock();    /* remove lock file! */
  948.       if ((ferror(mailfile)) || (fclose(mailfile) == EOF)) {
  949.           err = errno;
  950.           MoveCursor(LINES, 0);
  951.           Raw(OFF);
  952.           printf(catgets(elm_msg_cat, ElmSet, ElmCloseOnFolderFailed,
  953.                   "\nClose on folder %s failed!!\n"),
  954.                   cur_folder);
  955.           printf("** %s. **\n", error_description(err));
  956.           dprint(1, (debugfile, "Can't close on folder %s!!\n",
  957.              cur_folder));
  958.           rm_temps_exit();
  959.       }
  960.       if ((ferror(temp)) || (fclose(temp) == EOF)) {
  961.           err = errno;
  962.           MoveCursor(LINES, 0);
  963.           Raw(OFF);
  964.           printf(catgets(elm_msg_cat, ElmSet, ElmCloseOnTempFailed,
  965.                   "\nClose on temp file %s failed!!\n"), 
  966.                   cur_tempfolder);
  967.           printf("** %s. **\n", error_description(err));
  968.           dprint(1, (debugfile, "Can't close on temp file %s!!\n",
  969.              cur_tempfolder));
  970.           rm_temps_exit();
  971.       }
  972.       /* sanity check on append - is resulting temp file longer??? */
  973.       if ( bytes(cur_tempfolder) != mailfile_size) {
  974.          MoveCursor(LINES, 0);
  975.          Raw(OFF);
  976.          printf(catgets(elm_msg_cat, ElmSet, ElmLengthNESpool,
  977.            "\nnewmbox - length of mbox. != spool mailbox length!!\n"));
  978.         dprint(0, (debugfile, "newmbox - mbox. != spool mail length"));
  979.         rm_temps_exit();
  980.       }
  981.       if ((mailfile = fopen(cur_tempfolder,"r")) == NULL) {
  982.         err = errno;
  983.         MoveCursor(LINES,0);
  984.         Raw(OFF);
  985.         printf(catgets(elm_msg_cat, ElmSet, ElmCouldntReopenForTemp,
  986.            "\nCouldn't reopen file %s for use as temp file.\n"),
  987.                cur_tempfolder);
  988.         printf("** %s. **\n", error_description(err));
  989.         dprint(1, (debugfile,
  990.           "Error: Reopening %s as temp file failed!  errno %s (%s)\n",
  991.                cur_tempfolder, error_description(err), "read_headers"));
  992.         leave(0);
  993.       }
  994.     }
  995.     else 
  996.           rewind(mailfile);
  997.  
  998.     /* Sort folder *before* we establish the current message, so that
  999.      * the current message is based on the post-sort order.
  1000.      * Note that we have to set the global variable message_count
  1001.      * before the sort for the sort to correctly keep the correct
  1002.      * current message if we are only adding new messages here. */
  1003.  
  1004.     message_count = count;
  1005.     sort_mailbox(count, 1);
  1006.  
  1007.     /* Now lets figure what the current message should be.
  1008.      * If we are only reading in newly added messages from a mailfile
  1009.      * that already had some messages, current should remain the same.
  1010.      * If we have a folder of no messages, current should be zero.
  1011.      * Otherwise, if we have point_to_new on then the current message
  1012.      * is the first message of status NEW if there is one.
  1013.      * If we don't have point_to_new on or if there are no messages of
  1014.      * of status NEW, then the current message is the first message.
  1015.      */
  1016.     if(!(add_new_only && current != 0)) {
  1017.       if(count == 0)
  1018.         current = 0;
  1019.       else {
  1020.         current = 1;
  1021.         if (point_to_new) {
  1022.           for(another_count = 0; another_count < count; another_count++) {
  1023.         if(ison(headers[another_count]->status, NEW)) {
  1024.           current = another_count+1;
  1025.           goto found_new;
  1026.         }
  1027.           }
  1028.           for(another_count = 0; another_count < count; another_count++) {
  1029.         if(ison(headers[another_count]->status, UNREAD)) {
  1030.           current = another_count+1;
  1031.           goto found_new;
  1032.         }
  1033.           }
  1034.           switch (sortby) {
  1035.         case SENT_DATE:
  1036.         case RECEIVED_DATE:
  1037.         case MAILBOX_ORDER:
  1038.           current = count;
  1039.           }
  1040.           found_new: ;
  1041.         }
  1042.       }
  1043.     }
  1044.         get_page(current);
  1045.     return(count);
  1046. }
  1047.